package study.zookeeper.support.leader;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
import org.apache.curator.utils.CloseableUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;

/**
 * 基本原理：
 * 择一个根路径，例如"/leader_select"，多个机器同时向该根路径下创建临时顺序节点，
 * 如"/leader_latch/node_3"，"/leader_latch/node_1"，"/leader_latch/node_2"，节点编号最小(这里为node_1)的zk客户端成为leader
 * 没抢到Leader的节点都监听前一个节点的删除事件，在前一个节点删除后进行重新抢主
 */
@Slf4j
//@Component
public class LeaderApplicationRunner implements ApplicationRunner, LeaderLatchListener {

    /*  */
    private String path = "/leader_latch";
    /*  */
    private LeaderLatch latch;

    @Autowired
    private CuratorFramework client;

    /**
     * 抢主成功时触发，如果成为master则触发
     */
    @Override
    public void isLeader() {
        log.info(">>>>>> Leader: [{}]", latch.getId());

        //释放 leader 权限
        ThreadUtil.sleep(20 * 1000);
        log.info("close leader");
        CloseableUtils.closeQuietly(latch);
        //重新加入选举
        log.info("重新加入选举");
        join();
    }

    /**
     * 抢主失败时触发，如果从主节点变成非主节点则触发
     */
    @Override
    public void notLeader() {
        log.info(">>>>>> Not Leader: [{}]", latch.getId());
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        join();
    }

    private void join() {
        int random = RandomUtil.randomInt(10, 100);
        String id = "127.0.0.1:" + random;
        latch = new LeaderLatch(client, path, id, LeaderLatch.CloseMode.NOTIFY_LEADER);
        latch.addListener(this);
        //加入选举，start意味着参加选举，close意味着退出选举
        try {
            latch.start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
